This help file contains technical notes that provides solutions to some problems encountered when programming in FutureBASIC.
As new notes are added the updates will be made available via online services like America Online and AppleLink.
These notes should be considered Freeware and can be diseminated by FutureBASIC owners as widely as possible to ensure that all FutureBASIC owners are informed of their contents. Non-FutureBASIC owners are restricted from such distribution.
The POS(0) function fails to return the correct column position when used with PRINT%. Instead, it adds each subsequent column position to the previous one resulting in incorrect column values.
The POS function returns a character position within the current output line. It is thus a holdover from character based displays of old (remember 24x80 displays?).
Since the Macintosh uses a graphical display based on pixels, it is more natural to use a pixel based placement instead of columns. PRINT% was created to position text to within a resolution of 1 pixel and doesn't clear the buffer used by POS.
Use the WINDOW(_penH) and WINDOW(_penV) functions to get the current pixel position of the text pen instead of POS.
POS(0) does work correctly with the PRINT@ position which is character oriented.
When using the CALL statement to access external code resources, it is important to remember that CALL expects variables with type declarations to push them correctly on the stack. For example, the following pushes two integer variables, a long integer, and a string address onto the stack:
CALL _"fooh",999, ( var1%, var2%, var3&, var4$)
If, however, you pass an expression as a literal value, the CALL statement assumes that the expression represents a LONG INTEGER and places a long word on the stack, no matter what the actual expression value or size. For example:
CALL _"fooh", 999, ( 5, var2%, var3&, var4$)
pushes a long integer, an integer, a long integer, and a string address on the stack.
You can override this by placing an integer type declaration (%) BEFORE the actual value. This tells CALL the actual size of the expression to place onto the stack. To correct the above problem, you would thus use:
A program that doesn't use events may encounter problems using the FILES$ function on a Macintosh where Super Boomerang is running.
The problem surfaces when an event is pending in the event queue and a call to FILES$ is made without any fileType specified. When the get dialog appears, Super Boomerang takes charge and selects the last file chosen in that directory, clicks the Open button, and returns the file name and volRefNum% for that file. The file may or may not be the one you wanted to open.
The solution is to read the event with DIALOG ON and DIALOG OFF prior to using FILE$ to get a filename. This prevents Super Boomerang from taking over and opening any file it wants. For example:
DIALOG ON
DIALOG OFF
fileName$ = FILES$ (_fOpen, "", , v
olRefNum%)
LONG IF filename$ <> ""
' and so onx
END IF
will solve the problem even if you are not using events in other portions of your program.
Programs that handle events do not experience this problem.
(Thanks to Tony Andreoli for finding and debugging this)
When using INCLUDE files, it is important to remember the difference between _aplIncl (application only ), _resIncl (code resources ony), and _allIncl (both application & code resources) files.
When you use:
INCLUDE FILE _aplIncl
in an INCLUDE file, this tells the compiler that all FutureBASIC and Toolbox calls and functions should be supported in the INCLUDE.
However, when you use:
INCLUDE FILE _resIncl
the compiler uses the Mini-Runtime package which allows only a subset of FutureBASIC commands (those marked with an (M) in the Reference manual) and all Toolbox calls and functions.
Also, when using:
INCLUDE FILE _allIncl
note that this version compiles both types of resources into the INCLUDE file. This means that the pass compiling the _aplIncl may be successful while the pass creating the _resIncl could fail with an error.
Failure to take these differences into account can cause an error ("application only statement or function used in non-application program"). The solution is to replace the _resIncl or _allIncl with _aplIncl for application INLCUDES or strip out the offending application-only statements for a code resource INCLUDE.
Note that FutureBASIC's BCD floating point routines may not be used when compiling applications that use the mini-runtime.
ten in other languages for QuickBASICx to be used in FutureBASIC.
The key to using MBPCs or MBLC is to rebuild the code resource in the original environment without adding the BASICLib.asm file. This removes the header and callback routines to QB that are not supported in FutureBASIC.
It seems that many people are looking for and never see the MOUSE(0) function return a 1 (_click1) value indicating a single mouse click. In most cases the value returned is -1 (_click1nDrag).
The discrepency occurs between the time the mouse is initially clicked and the time its reported by the MOUSE(0) function. MOUSE(0) will always return the state of the button at the time of inquiry and if the button is still down the message will be _click1nDrag, not _click1.
This is most noticeable on new, faster machines with higher clock rates. It is almost impossible in some cases to ever see a _click1 since the application vectors so fast that the MOUSE(0) statement see's a finger holding the mouse button down and reports _click1nDrag.
The solution is to use the ABS function to return a value of _click1 no matter whether MOUSE(0) returns _click1 or _click1nDrag.
While MacinTalkx has never really been supported by Apple, using it in ZBASIC was made easy through the use of the OPEN TALK and TALK statements. While its not mentioned in the manuals (see the FutureBASIC Help file) these statements are still available and usable in FutureBASIC even under System 7.
To make MacinTalk accessible its necessary to modify a STR# resource in the Futurex Extras file. Use the following steps to make the change:
1. Run ResEdit (FutureBASIC should not be running)
2. Open the Futurex Extras file
3. Open the STR# resource picker window
4. Open STR# 194
5. Locate: item # 14 "No MacinTalk Reader"
6. Replace: item #14 with "" (clear text in item only, don't delete)
7. Choose Save from the File menu
8. Close all windows and quit ResEdit.
Why the change works:
The MacinTalk driver has two speech options, one allows you to use English phrases for a speech string, the other enables you to use phonemes. The text in the STR# makes MacinTalk look for a phoneme file which isn't found. This results in a "File Not Found" error.
Using MacinTalk:
You can include the following function in your programs to make using MacinTalk even easier. Pass it a string and any changes to the speech settings and it does the work of opening the driver, speaking the string, and closing the driver.
Modify to suit your own tastes. Ideally you can probably set the parameters to default values and just pass a string for it to speak.
' speech$...text to say
' speed%... rate of speech (85 - 425 words/minute,
' sex%......male or female voice (never implemented by
Apple)
LOCAL FN DoTalk (speech$,speed%,pitch%,talk%,sex%) OPEN TALK, #-4, "", 512
TALK #-4, speed%, pitch%, talk%, sex%
PRINT #-4, speech$
CLOSE #-4
END FN
txt$ = "FutureBASIC can talk!)
FN DoTalk (txt$, 150, 110, 0, 0)
Warning:
It is recommended that you use the above routine to open and then close MacinTalk after each use since the Sound Manager on newer machines is disconnected when MacinTalk is operating. This can prevent system beeps and other sound resources from being played.
Also, there is no guarantee that MacinTalk will work on all machines.
(Thanks to a host of people who wanted to see MacinTalk again.)
There is a problem in the reading and writing of record type variables using READ and WRITE. This bug causes the writing of record zero to actually write an incorrect length of data (many times larger) than the actual record size. The example below demonstrates the problem:
DIM RECORD test 'define a record
DIM rect.8
DIM 25 tmp$
DIM END RECORD .test
DIM testRec.test 'define record variable
CALL SETRECT (testRec.top%, 10, 10, 20, 20)
testRec.tmp$ = "Record #1"
OPEN "R", 1, "Test RW", _test, SYSTEM (_aplVol)
RECORD #1, 0 'set record number
WRITE #1, testRec 'write data to disk
CALL SETRECT (testRec.top%, 50, 50, 70, 70)
testRec.tmp$ = "Record #2"
RECORD #1, 1 'set record number
WRITE #1, testRec 'write data to disk
CLOSE #1
OPEN "R", 1, "Test RW", _test, SYSTEM (_aplVol)
RECORD #1, 0
'set record number
READ #1, testRec 'read data from disk
PRINT "---
RECORD #1 ---" 'show record data
PRINT testRec.top%,testRec.left%
PRINT testRec.bottom%,testRec.right%
PRINT tmp$
RECORD #1, 1 'set record number
READ #1, testRec
'read data from disk
CLOSE #1
PRINT "--- RECORD #1 ---" 'show record data
PRINT testRec.top%,testRec.left%
PRINT testRec.bottom%,testRec.right%
PRINT tmp$
STOP
Fixing this Bug:
You can use ResEdit to correct this bug by modifying a word in a single CODE resource of FutureBASIC. The steps include:
1. Run ResEdit.
2. Open FutureBASIC.
3. Open the CODE resource picker (shows all CODE resources) 4. Open CODE #9.
5. Find offset &H28B6
6. Replace &HEE8C3650 with &HEE8C3642
7. Save your changes.
8. Close FutureBASIC and quit ResEdit.
(Thanks to Miro Valach for finding this nasty one.)